package
{
	import flash.display.*;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.getTimer;
	
	/** This class builds a growing shape that grows to match the given type */
	public class ChildPolygon extends Polygon
	{
		public static const GROW_ANIMATION_TIME:uint = 2000, FINAL_ANIMATION_TIME:uint = 2000;
		public static const OUTLINE_COLOR:uint = 0x444444, INTERIOR_COLOR:uint = 0xAAAAAA, FINAL_OUTLINE_COLOR:uint = 0xAAAA44, FINAL_INTERIOR_COLOR:uint = 0xFFFF88;
		// public variables
		public var MIN_X:Number, MAX_X:Number, MIN_Y:Number, MAX_Y:Number, WIDTH:Number, HEIGHT:Number;
		public var valid:Boolean; // determined after shape built
		public var error:String;
		// private objects
		private var closedPolygon:ClosedPolygon; // reference to original closed polygon
		private var tcentroid:Point, tdiagonalI:Point, tcenter:Point;
		private var targetDrawPoints:Array, targetPoints:Array;
		private var growPoints:Array; // array of _targetPoints, representing polar coordinates telling us how shape grows
		// private variables
		private var minArea:Number;
		private var _color:uint =FINAL_INTERIOR_COLOR;
		private var shape:Sprite;
		// for growth
		private var starti:uint; // the starting index as we loop through _targetPoints (allows randomness)
		private var timestamp:int, fps:int;
		// for final child
		private var eyeL:Eye, eyeR:Eye;
		private var nose:Shape;
		private var mouth:Mouth;
		private var distanceToEdge:Number; // animate moving off screen
		private var ishapePoint:Point;
		// getters
		override public function get color():uint{return _color;}
		override public function set color(u:uint):void{_color=u;}
		
		public function ChildPolygon(closedPolygon:ClosedPolygon, type:String, minArea:Number=0)
		{
			super(null, 0,0);
			this.closedPolygon = closedPolygon;
			this.targetDrawPoints = closedPolygon.drawPoints;
			this.targetPoints = DrawPoint.toGeomPoints(targetDrawPoints);
			this.type = type;
			this.minArea = minArea;
			// find width and height of bounding box by first finding min and max
			MIN_X = Number.MAX_VALUE;
			MAX_X = -Number.MIN_VALUE;
			MIN_Y = Number.MAX_VALUE;
			MAX_Y = -Number.MIN_VALUE;
			
			// also turn DrawPoints into Points
			for each (var p:DrawPoint in drawPoints)
			{
				if (p.x < MIN_X) MIN_X = p.x;
				if (p.x > MAX_X) MAX_X = p.x;
				if (p.y < MIN_Y) MIN_Y = p.y;
				if (p.y > MAX_Y) MAX_Y = p.y;
			}
			WIDTH = MAX_X - MIN_X;
			HEIGHT = MAX_Y - MIN_Y;
			this.addEventListener(Event.ADDED, handleAdded);
		}
		private function handleAdded(event:Event):void 
		{
			this.removeEventListener(Event.ADDED, handleAdded);
			//trace("Area, this, min", closedPolygon.area, minArea);
			if (closedPolygon.area < minArea)
			{
				GeometryGameItem(parent.parent).processCommand("child", "error", this, new Array("This shape is too small."));
			} else
			{
				shape = new Sprite();
				this.addChild(shape);			
				setupGrowth();
			}
		}
		/** This is the critical function for this class, which determines the way that the shape will grow */
		private function setupGrowth():void
		{
			var p:Point, pp:Point, pmin:Point;
			var A:Point, B:Point, C:Point, D:Point, Ct:Point, Dt:Point, I:Point;
			var a:Number, d:Number, dmin:Number;
			var ai:Number, bi:Number, ci:Number, di:Number, ab:Number, bc:Number, cd:Number, ad:Number, ac:Number, bd:Number;
			var angAIB:Number, angBIC:Number, angCID:Number, angAID:Number; // with I as center point
			var angBAD:Number, angBAC:Number, angCAD:Number; // with A as center point
			var angABC:Number, angABD:Number, angCBD:Number; // with A as center point
			var angBCD:Number, angACB:Number, angACD:Number; // with A as center point
			var angADC:Number, angADB:Number, angBDC:Number; // with A as center point
			var aiori:Number, biori:Number, ciori:Number, diori:Number;
			var abori:Number, bcori:Number, cdori:Number, daori:Number, acori:Number; 
			var baori:Number, cbori:Number, dcori:Number, adori:Number, caori:Number;; 
			var tdir:int, dir:int; // direction of target points, direction of mapped points
			var i:uint;
			var _type:String = this.type; // use temp var in case we want some type of shape to grow as another
			var _targetPoints:Array;
			points = new Array();
			growPoints = new Array();
			var npoints:uint;
			var typeSplit:Array = type.split("_");
			switch (typeSplit[typeSplit.length-1])
			{
				case "dodecagon": npoints=12; break;
				case "decagon": npoints=10; break;
				case "nonagon": case "enneagon": npoints=9; break;
				case "octagon": npoints=8; break;
				case "heptagon": npoints=7; break;
				case "hexagon": npoints=6; break;
				case "pentagon": npoints=5; break;
				case "quadrilateral": case "quadrangle": npoints=4; break;
				case "triangle": npoints=3; break;
			}
			switch (_type)
			{
				case "dodecagon": case "decagon": case "nonagon": case "enneagon": case "octagon": case "heptagon": case "hexagon": case "pentagon": case "quadrilateral": case "quadrangle": case "triangle":
				case "concave_dodecagon": case "concave_decagon": case "concave_nonagon": case "concave_enneagon": case "concave_octagon": case "concave_heptagon": case "concave_hexagon": case "concave_pentagon": case "concave_quadrilateral": case "concave_quadrangle":
				case "convex_dodecagon": case "convex_decagon": case "convex_nonagon": case "convex_enneagon": case "convex_octagon": case "convex_heptagon": case "convex_hexagon": case "convex_pentagon": case "convex_quadrilateral": case "convex_quadrangle":
					_targetPoints = addRandomPoints(targetPoints, npoints-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdiagonalI = Polygon.DiagonalIntersection(_targetPoints);
					shape.x = tcentroid.x;
					shape.y = tcentroid.y;
					// loop through _targetPoints finding distance from vertices to centroids, setup polar coordinates
					starti = Math.floor(Math.random()*npoints); //start the growing process from a random point 				
					//starti=0;
					i = starti;
					for (i=0; i < npoints; i++)
					{
						p = _targetPoints[(starti+i)%npoints];
						pp = new Point(MathUtilities.distance(p.x, p.y, tcentroid.x, tcentroid.y), MathUtilities.calcAngle(p,tcentroid));
						points.push(new Point(0, 0));
						growPoints.push(pp);
					}
					break;
				case "trapezoid":				
					///        A  ----------   B
					///          /          \
					///         /     *I     \
					///      D /______________\ C
					
					// Angle B is opposite computed corner, angle A is adjacent along non parallel side, C is adjacent along parallel side, D is to be computed
					// side b and c are not parallel, b is known c is computed
					// we need to figure out which two sides are closer to parallel
					//trace("point 0", _targetPoints[0]);
					//trace("point 1", _targetPoints[1]);
					//trace("point 2", _targetPoints[2]);
					//trace("point 3", _targetPoints[3]);
					//trace("0-to-1", (MathUtilities.calcRotation(_targetPoints[0], _targetPoints[1])+180)%180, "2-to-3", (MathUtilities.calcRotation(_targetPoints[2], _targetPoints[3])+180)%180, "3-to-0", (MathUtilities.calcRotation(_targetPoints[3], _targetPoints[0])+180)%180, "1-to-2", (MathUtilities.calcRotation(_targetPoints[1], _targetPoints[2])+180)%180); 
					trace(targetPoints, 4-targetPoints.length);
					_targetPoints = addRandomPoints(targetPoints, 4-targetPoints.length);
					trace(_targetPoints);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdiagonalI = Polygon.DiagonalIntersection(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);
					// which sides are parallel
					if ( Math.abs((MathUtilities.calcRotation(_targetPoints[0], _targetPoints[1])+180)%180 - (MathUtilities.calcRotation(_targetPoints[2], _targetPoints[3])+180)%180) <= Math.abs((MathUtilities.calcRotation(_targetPoints[0], _targetPoints[3])+180)%180 - (MathUtilities.calcRotation(_targetPoints[1], _targetPoints[2])+180)%180))
					{
						// which angles are closest to right: ang0, ang3 or angB, angC?						
						if (Math.random() < .5)
						{
							//trace("sides parallel: top bottom", tdir, "same direction");
							// angles at 0 and 3
							A = _targetPoints[0];B = _targetPoints[1];C = _targetPoints[2];Dt = _targetPoints[3];	
							dir = tdir;
						} else
						{
							//trace("sides parallel: top bottom", tdir, "opposite direction");
							// angles at 1 and 2
							A = _targetPoints[1];B = _targetPoints[0];C = _targetPoints[3];Dt = _targetPoints[2];
							dir = -tdir;
						}
					} else
					{
						// which angles are closest to right: ang0, ang3 or angB, angC?						
						if (Math.random() < .5)
						{
							//trace("sides parallel: left right", tdir, "opposite direction");
							// angles at 0 and 1
							A = _targetPoints[0];B = _targetPoints[3];C = _targetPoints[2];Dt = _targetPoints[1];	
							
							dir = -tdir;
						} else
						{
							//trace("sides parallel: left right", tdir, "same direction");
							// angles at 2 and 3
							A = _targetPoints[2];B = _targetPoints[1];C = _targetPoints[0];Dt = _targetPoints[3];
							dir = -tdir;
						}
					}
					angABC = MathUtilities.calcAcuteAngleBetween(A, C, B);
					angBCD = Math.PI - angABC;
					angACB = MathUtilities.calcAcuteAngleBetween(A, B, C);
					angACD = angBCD - angACB;
					angCAD = MathUtilities.calcAcuteAngleBetween(C, Dt, A);
					angADC = Math.PI - angCAD - angACD;
					ac = MathUtilities.distanceP(A, C);
					ad = MathUtilities.lawOfSines(ac, angADC, 0, angACD);
					daori = MathUtilities.calcAngle(Dt, A);
					D = new Point(A.x+ad*Math.sin(daori), A.y-ad*Math.cos(daori));
					I = Polygon.DiagonalIntersection(new Array(A,B,C,D));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					di = MathUtilities.distanceP(D, I);
					diori = MathUtilities.calcAngle(D,I);
					shape.x = this.tdiagonalI.x;
					shape.y = this.tdiagonalI.y;
					
					//trace("orientation to C", MathUtilities.radToDeg(ciori), MathUtilities.radToDeg(angCID), MathUtilities.radToDeg(ciori + dir*angCID));
					points.push(new Point(0, 0));
					growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0));
					growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0));
					growPoints.push(new Point(ci, ciori));
					points.push(new Point(0, 0));
					growPoints.push(new Point(di, diori));
					
					break;
					
				case "right_trapezoid":				
					///        A  ----------   B
					///           i         \
					///           i   *I     \
					///        D  i___________\ C
					
					// in this case put at center of diagonals, because I'm not smart enough to use the centroid
					// Angle B is opposite computed corner, angle A is adjacent along non parallel side, C is adjacent along parallel side, D is to be computed
					// side b and c are not parallel, b is known c is computed
					// we need to figure out which two sides are closer to parallel
					//trace("point 0", _targetPoints[0]);
					//trace("point 1", _targetPoints[1]);
					//trace("point 2", _targetPoints[2]);
					//trace("point 3", _targetPoints[3]);
					//trace("0-to-1", (MathUtilities.calcRotation(_targetPoints[0], _targetPoints[1])+180)%180, "2-to-3", (MathUtilities.calcRotation(_targetPoints[2], _targetPoints[3])+180)%180, "3-to-0", (MathUtilities.calcRotation(_targetPoints[3], _targetPoints[0])+180)%180, "1-to-2", (MathUtilities.calcRotation(_targetPoints[1], _targetPoints[2])+180)%180); 
					_targetPoints = addRandomPoints(targetPoints, 4-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdiagonalI = Polygon.DiagonalIntersection(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);
					// which sides are parallel
					if ( Math.abs((MathUtilities.calcRotation(_targetPoints[0], _targetPoints[1])+180)%180 - (MathUtilities.calcRotation(_targetPoints[2], _targetPoints[3])+180)%180) <= Math.abs((MathUtilities.calcRotation(_targetPoints[0], _targetPoints[3])+180)%180 - (MathUtilities.calcRotation(_targetPoints[1], _targetPoints[2])+180)%180))
					{
						// which angles are closest to right: ang0, ang3 or angB, angC?						
						if (Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[3], _targetPoints[0])-90) + Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[3])-90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1])-90) + Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[3], _targetPoints[2])-90))
						{
							//trace("sides parallel: top bottom", tdir, "0,3 right");
							// angles at 0 and 3
							A = _targetPoints[0];B = _targetPoints[1];C = _targetPoints[2];	
							dir = tdir;
						} else
						{
							//trace("sides parallel: top bottom", tdir, "1,2 right");
							// angles at 1 and 2
							A = _targetPoints[1];B = _targetPoints[0];C = _targetPoints[3];
							dir = -tdir;
						}
					} else
					{
						// which angles are closest to right: ang0, ang3 or angB, angC?						
						if (Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[3], _targetPoints[0])-90) + Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1])-90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[3])-90) + Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[3], _targetPoints[2])-90))
						{
							//trace("sides parallel: top bottom", tdir, "0,1 right");
							// angles at 0 and 1
							A = _targetPoints[0];B = _targetPoints[3];C = _targetPoints[2];	
							dir = -tdir;
						} else
						{
							//trace("sides parallel: top bottom", tdir, "2,3 right");
							// angles at 2 and 3
							A = _targetPoints[2];B = _targetPoints[1];C = _targetPoints[0];
							dir = -tdir;
						}
					}
					angABC = MathUtilities.calcAcuteAngleBetween(A, C, B);
					angBCD = Math.PI - angABC;
					angACB = MathUtilities.calcAcuteAngleBetween(A, B, C);
					angACD = angBCD - angACB;
					angADC = Math.PI/2;
					ac = MathUtilities.distanceP(A, C);
					ad = MathUtilities.lawOfSines(ac, angADC, 0, angACD);
					daori = MathUtilities.calcAngle(A, B) - dir*Math.PI/2;
					D = new Point(A.x+ad*Math.sin(daori), A.y-ad*Math.cos(daori));
					I = Polygon.DiagonalIntersection(new Array(A,B,C,D));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					di = MathUtilities.distanceP(D, I);
					diori = MathUtilities.calcAngle(D,I);
					shape.x = this.tdiagonalI.x;
					shape.y = this.tdiagonalI.y;
					
					//trace("orientation to C", MathUtilities.radToDeg(ciori), MathUtilities.radToDeg(angCID), MathUtilities.radToDeg(ciori + dir*angCID));
					points.push(new Point(0, 0));
					growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0));
					growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0));
					growPoints.push(new Point(ci, ciori));
					points.push(new Point(0, 0));
					growPoints.push(new Point(di, diori));
					break;
				case "isosceles_trapezoid":				
					///        A    ----------   B
					///            /         \
					///           /   *I      \
					///        D /_____________\ C
					
					//trace("point 0", _targetPoints[0]);
					//trace("point 1", _targetPoints[1]);
					//trace("point 2", _targetPoints[2]);
					//trace("point 3", _targetPoints[3]);
					// Angle B is opposite computed corner, angle A is adjacent along non parallel side, C is adjacent along parallel side, D is to be computed
					// side b and c are not parallel, b is known c is computed
					// we need to figure out which two sides are closer to parallel
					_targetPoints = addRandomPoints(targetPoints, 4-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdiagonalI = Polygon.DiagonalIntersection(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which sides are parallel
					if ( Math.abs((MathUtilities.calcRotation(_targetPoints[0], _targetPoints[1])+180)%180 - (MathUtilities.calcRotation(_targetPoints[2], _targetPoints[3])+180)%180) <= Math.abs((MathUtilities.calcRotation(_targetPoints[0], _targetPoints[3])+180)%180 - (MathUtilities.calcRotation(_targetPoints[1], _targetPoints[2])+180)%180))
					{
						// which angles are closest to right: ang0, ang3 or angB, angC?						
						if (Math.random() < .5)
						{
							//trace("sides parallel: top bottom", tdir, "same direction");
							// angles at 0 and 3
							A = _targetPoints[0];B = _targetPoints[1];C = _targetPoints[2];	
							dir = tdir;
						} else
						{
							//trace("sides parallel: top bottom", tdir, "opposite direction");
							// angles at 1 and 2
							A = _targetPoints[1];B = _targetPoints[0];C = _targetPoints[3];
							dir = -tdir;
						}
					} else
					{
						// which angles are closest to right: ang0, ang3 or angB, angC?						
						if (Math.random() < .5)
						{
							//trace("sides parallel: left right", tdir, "opposite direction");
							// angles at 0 and 1
							A = _targetPoints[0];B = _targetPoints[3];C = _targetPoints[2];	
							dir = -tdir;
						} else
						{
							//trace("sides parallel: left right", tdir, "same direction");
							// angles at 2 and 3
							A = _targetPoints[2];B = _targetPoints[1];C = _targetPoints[0];
							dir = -tdir;
						}
					}
					angABC = MathUtilities.calcAcuteAngleBetween(A, C, B);
					angBCD = Math.PI - angABC;
					angACB = MathUtilities.calcAcuteAngleBetween(A, B, C);
					angACD = angBCD - angACB;
					angBAD = angABC;
					//angBAC = MathUtilities.calcAcuteAngleBetween(B, C, A);
					//angCAD = angBAD - angBAC;
					//angADC = Math.PI - angCAD - angACD;
					ad = MathUtilities.distanceP(B, C);
					daori = MathUtilities.calcAngle(A, B) -dir*(Math.PI - angBAD);
					D = new Point(A.x+ad*Math.sin(daori), A.y-ad*Math.cos(daori));
					I = Polygon.DiagonalIntersection(new Array(A,B,C,D));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					di = MathUtilities.distanceP(D, I);
					diori = MathUtilities.calcAngle(D,I);
					shape.x = this.tdiagonalI.x;
					shape.y = this.tdiagonalI.y;
					
					trace("orientation to C", MathUtilities.radToDeg(ciori), MathUtilities.radToDeg(angCID), MathUtilities.radToDeg(ciori + dir*angCID));
					points.push(new Point(0, 0));
					growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0));
					growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0));
					growPoints.push(new Point(ci, ciori));
					points.push(new Point(0, 0));
					growPoints.push(new Point(di, diori));
					
					break;
				case "kite":
					_targetPoints = addRandomPoints(targetPoints, 4-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdiagonalI = Polygon.DiagonalIntersection(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which two pairs of adjacent sides are closest to congruent
					if ( Math.abs(MathUtilities.distanceP(_targetPoints[0], _targetPoints[1]) - MathUtilities.distanceP(_targetPoints[1], _targetPoints[2])) + Math.abs(MathUtilities.distanceP(_targetPoints[2], _targetPoints[3]) - MathUtilities.distanceP(_targetPoints[3], _targetPoints[0])) <= Math.abs(MathUtilities.distanceP(_targetPoints[3], _targetPoints[0]) - MathUtilities.distanceP(_targetPoints[0], _targetPoints[1])) + Math.abs(MathUtilities.distanceP(_targetPoints[1], _targetPoints[2]) - MathUtilities.distanceP(_targetPoints[2], _targetPoints[3])))
					{ // (0-1, 1-2), (2-3, 3-0)
						A = _targetPoints[1]; B = _targetPoints[2]; C = _targetPoints[3];
						dir = tdir;
					} else
					{ // (3-0, 0-1), (1-2, 2-3)
						A = _targetPoints[0]; B = _targetPoints[1]; C = _targetPoints[2];
						dir = tdir;
					}
					// complete triangle from A-B-C
					ab = MathUtilities.distanceP(A,B);
					bc = MathUtilities.distanceP(B,C);
					ac = MathUtilities.distanceP(A,C);
					angBAC = MathUtilities.calcAcuteAngleBetween(B,C,A);
					angBAD = 2*angBAC;
					baori = MathUtilities.calcAngle(B, A);
					daori = baori + dir * angBAD;
					D = new Point(A.x + ab * Math.sin(daori), A.y - ab * Math.cos(daori));
					I = Polygon.DiagonalIntersection(new Array(A,B,C,D));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					di = MathUtilities.distanceP(D, I);
					diori = MathUtilities.calcAngle(D,I);
					shape.x = this.tdiagonalI.x;
					shape.y = this.tdiagonalI.y;
					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					points.push(new Point(0, 0)); growPoints.push(new Point(di, diori));
					
					break;
				case "parallelogram":
					_targetPoints = addRandomPoints(targetPoints, 4-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdiagonalI = Polygon.DiagonalIntersection(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					starti = Math.floor(Math.random()*4);
					A = _targetPoints[starti]; B = _targetPoints[(starti+1)%_targetPoints.length]; C = _targetPoints[(starti+2)%_targetPoints.length]; 
					dir = tdir;
					bc = MathUtilities.distanceP(B,C);
					angABC = MathUtilities.calcAcuteAngleBetween(A,C,B);
					angBAD = Math.PI - angABC;
					baori = MathUtilities.calcAngle(B, A);
					daori = baori + dir * angBAD;
					D = new Point(A.x + bc * Math.sin(daori), A.y - bc * Math.cos(daori));
					I = Polygon.DiagonalIntersection(new Array(A,B,C,D));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					di = MathUtilities.distanceP(D, I);
					diori = MathUtilities.calcAngle(D,I);
					shape.x = this.tdiagonalI.x;
					shape.y = this.tdiagonalI.y;
					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					points.push(new Point(0, 0)); growPoints.push(new Point(di, diori));
					
					break;
				case "rectangle":
					_targetPoints = addRandomPoints(targetPoints, 4-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdiagonalI = Polygon.DiagonalIntersection(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					starti = Math.floor(Math.random()*4);
					A = _targetPoints[starti]; B = _targetPoints[(starti+1)%_targetPoints.length]; Ct = _targetPoints[(starti+2)%_targetPoints.length];
					dir = tdir; 
					ab = MathUtilities.distanceP(A, B);
					// get the distance from b to c as the distance from b to the line parallel to ab on which c lies
					bc =  MathUtilities.distanceP(B, Ct)*Math.cos(Math.abs(Math.PI/2 - MathUtilities.calcAcuteAngleBetween(A, Ct, B)));
					angABC = Math.PI/2;
					angBAD = Math.PI/2;
					abori = MathUtilities.calcAngle(A, B);
					cbori = abori - dir * angABC;
					C = new Point(B.x + bc * Math.sin(cbori), B.y - bc * Math.cos(cbori));
					baori = MathUtilities.calcAngle(B, A);
					daori = baori + dir * angBAD;
					D = new Point(A.x + bc * Math.sin(daori), A.y - bc * Math.cos(daori));
					I = Polygon.DiagonalIntersection(new Array(A,B,C,D));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					di = MathUtilities.distanceP(D, I);
					diori = MathUtilities.calcAngle(D,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					points.push(new Point(0, 0)); growPoints.push(new Point(di, diori));
					break;
				case "rhombus":
					_targetPoints = addRandomPoints(targetPoints, 4-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdiagonalI = Polygon.DiagonalIntersection(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					starti = Math.floor(Math.random()*4);
					A = _targetPoints[starti]; B = _targetPoints[(starti+1)%_targetPoints.length]; Ct = _targetPoints[(starti+2)%_targetPoints.length]; 
					dir = tdir; 
					ab = MathUtilities.distanceP(A, B);
					angABC = MathUtilities.calcAcuteAngleBetween(A,Ct,B);
					angBAD = Math.PI - angABC;
					abori = MathUtilities.calcAngle(A, B);
					cbori = abori - dir * angABC;
					C = new Point(B.x + ab * Math.sin(cbori), B.y - ab * Math.cos(cbori));
					baori = MathUtilities.calcAngle(B, A);
					daori = baori + dir * angBAD;
					D = new Point(A.x + ab * Math.sin(daori), A.y - ab * Math.cos(daori));
					I = Polygon.DiagonalIntersection(new Array(A,B,C,D));	
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					di = MathUtilities.distanceP(D, I);
					diori = MathUtilities.calcAngle(D,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					points.push(new Point(0, 0)); growPoints.push(new Point(di, diori));
					
					break;
				case "square":
				case "regular_quadrilateral":
				case "regular_quadrangle":
				case "right_rhombus":
					_targetPoints = addRandomPoints(targetPoints, 4-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdiagonalI = Polygon.DiagonalIntersection(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					starti = Math.floor(Math.random()*4);
					A = _targetPoints[starti]; B = _targetPoints[(starti+1)%_targetPoints.length]; 
					dir = tdir; 
					ab = MathUtilities.distanceP(A, B);
					angABC = Math.PI/2;
					angBAD = Math.PI/2;
					abori = MathUtilities.calcAngle(A, B);
					cbori = abori - dir * angABC;
					C = new Point(B.x + ab * Math.sin(cbori), B.y - ab * Math.cos(cbori));
					baori = MathUtilities.calcAngle(B, A);
					daori = baori + dir * angBAD;
					D = new Point(A.x + ab * Math.sin(daori), A.y - ab * Math.cos(daori));
					I = Polygon.DiagonalIntersection(new Array(A,B,C,D));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					di = MathUtilities.distanceP(D, I);
					diori = MathUtilities.calcAngle(D,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					points.push(new Point(0, 0)); growPoints.push(new Point(di, diori));
					break;
				case "triangle":
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					shape.x = tcentroid.x;
					shape.y = tcentroid.y;
					// loop through _targetPoints finding distance from vertices to centroids, setup polar coordinates
					starti = Math.floor(Math.random()*3); //start the growing process from a random point 				
					//starti=0;
					i = starti;
					for (i=0; i < 3; i++)
					{
						p = _targetPoints[(starti+i)%3];
						pp = new Point(MathUtilities.distance(p.x, p.y, tcentroid.x, tcentroid.y), MathUtilities.calcAngle(p,tcentroid));
						points.push(new Point(0, 0));
						growPoints.push(pp);
					}
					break;
				case "isosceles_triangle":
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					starti = Math.floor(Math.random()*3);
					// which two pairs of adjacent sides are closest to congruent
					if ( Math.abs(MathUtilities.distanceP(_targetPoints[0], _targetPoints[1]) - MathUtilities.distanceP(_targetPoints[1], _targetPoints[2]))  <= Math.abs(MathUtilities.distanceP(_targetPoints[2], _targetPoints[0]) - MathUtilities.distanceP(_targetPoints[0], _targetPoints[1])) && Math.abs(MathUtilities.distanceP(_targetPoints[0], _targetPoints[1]) - MathUtilities.distanceP(_targetPoints[1], _targetPoints[2]))  <= Math.abs(MathUtilities.distanceP(_targetPoints[2], _targetPoints[0]) - MathUtilities.distanceP(_targetPoints[1], _targetPoints[2])))
					{ // (0-1, 1-2)
						A = _targetPoints[1]; B = _targetPoints[2]; Ct = _targetPoints[0];
						dir = tdir;
					} else if ( Math.abs(MathUtilities.distanceP(_targetPoints[2], _targetPoints[0]) - MathUtilities.distanceP(_targetPoints[0], _targetPoints[1]))  <= Math.abs(MathUtilities.distanceP(_targetPoints[0], _targetPoints[1]) - MathUtilities.distanceP(_targetPoints[1], _targetPoints[2])) && Math.abs(MathUtilities.distanceP(_targetPoints[2], _targetPoints[0]) - MathUtilities.distanceP(_targetPoints[0], _targetPoints[1]))  <= Math.abs(MathUtilities.distanceP(_targetPoints[1], _targetPoints[2]) - MathUtilities.distanceP(_targetPoints[2], _targetPoints[0])))
					{// (2-0, 0-1)
						A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
						dir = tdir;
					} else
					{// (1-2, 2-0)
						A = _targetPoints[2]; B = _targetPoints[0]; Ct = _targetPoints[1];
						dir = tdir;
					}
						
						// 
					ab = MathUtilities.distanceP(A, B);
					angBAC = MathUtilities.calcAcuteAngleBetween(B, Ct, A);
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ab * Math.sin(caori), A.y - ab * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "equilateral_triangle":
				case "regular_triangle":
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					starti = Math.floor(Math.random()*3);
					// which two pairs of adjacent sides are closest to congruent
					if ( Math.abs(MathUtilities.distanceP(_targetPoints[0], _targetPoints[1]) - MathUtilities.distanceP(_targetPoints[1], _targetPoints[2]))  <= Math.abs(MathUtilities.distanceP(_targetPoints[2], _targetPoints[0]) - MathUtilities.distanceP(_targetPoints[0], _targetPoints[1])))
					{ // (0-1, 1-2)
						A = _targetPoints[1]; B = _targetPoints[2];
						dir = tdir;
					} else
					{ // (2-0, 0-1)
						A = _targetPoints[0]; B = _targetPoints[1];
						dir = tdir;
					} 
					ab = MathUtilities.distanceP(A, B);
					angBAC = Math.PI/3;
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ab * Math.sin(caori), A.y - ab * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "scalene_triangle":
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
					dir = tdir;
					ab = MathUtilities.distanceP(A, B);
					ac = MathUtilities.distanceP(A, Ct);
					angBAC = MathUtilities.calcAcuteAngleBetween(B, Ct, A);
					if (Math.abs(ab - ac) < DrawingPanel(this.parent).length_threshold_pixels)
					{
						ac = ac * .75;
						// just in case, make sure other pair aren't now equal too
						bc = MathUtilities.lawOfCosines(ab, ac, 0, angBAC);
						if ( Math.abs(bc - ab) < DrawingPanel(this.parent).length_threshold_pixels || Math.abs(bc - ac) < DrawingPanel(this.parent).length_threshold_pixels)
						{
							ac = ac * .67;	
						}
					}
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ac * Math.sin(caori), A.y - ac * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "right_triangle":
					///      A ------- B
					///		   i    /
					///        i   /
					///      C i /     
					
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which angle is closest to 90?
					if ( Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[1], _targetPoints[2]) - 90) && Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[0], _targetPoints[1]) - 90))
					{ // angle 0
						A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
						dir = tdir;
					} else if ( Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[1], _targetPoints[0]) - 90) && Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[0], _targetPoints[2]) - 90))
					{ // angle 1
						A = _targetPoints[1]; B = _targetPoints[2]; Ct = _targetPoints[0];
						dir = tdir;
					} else 
					{ // angle 2
						A = _targetPoints[2]; B = _targetPoints[0]; Ct = _targetPoints[1];
						dir = tdir;
					}
					ac = MathUtilities.distanceP(A, Ct);
					angBAC = Math.PI/2;
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ac * Math.sin(caori), A.y - ac * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "acute_triangle":
					///      A ------- B
					///		   \    /
					///         \  /
					///       C  \  
					
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which angle is greatest?
					if ( MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[1], _targetPoints[2]) && MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[0], _targetPoints[1]))
					{ // angle 0
						A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
						dir = tdir;
					} else if ( MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[1], _targetPoints[0]) && MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[0], _targetPoints[2]))
					{ // angle 1
						A = _targetPoints[1]; B = _targetPoints[2]; Ct = _targetPoints[0];
						dir = tdir;
					} else 
					{ // angle 2
						A = _targetPoints[2]; B = _targetPoints[0]; Ct = _targetPoints[1];
						dir = tdir;
					}
					ac = MathUtilities.distanceP(A, Ct);
					angBAC = MathUtilities.calcAcuteAngleBetween(B, Ct, A);
					if (angBAC >= Math.PI/2) angBAC = Math.PI/3; // default to 60 degrees for incorrect figures
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ac * Math.sin(caori), A.y - ac * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "obtuse_triangle":
					///      A ------- B
					///		  /    /
					///      /  /
					///  C  //     
					
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which angle is greatest?
					if ( MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[1], _targetPoints[2]) && MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[0], _targetPoints[1]))
					{ // angle 0
						A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
						dir = tdir;
					} else if ( MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[1], _targetPoints[0]) && MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[0], _targetPoints[2]))
					{ // angle 1
						A = _targetPoints[1]; B = _targetPoints[2]; Ct = _targetPoints[0];
						dir = tdir;
					} else 
					{ // angle 2
						A = _targetPoints[2]; B = _targetPoints[0]; Ct = _targetPoints[1];
						dir = tdir;
					}
					ac = MathUtilities.distanceP(A, Ct);
					angBAC = MathUtilities.calcAcuteAngleBetween(B, Ct, A);
					if (angBAC <= Math.PI/2) angBAC = Math.PI/3*2; // default to 120 degrees for incorrect figures
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ac * Math.sin(caori), A.y - ac * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "isosceles_right_triangle":
				case "right_isosceles_triangle":
					///      A ------- B
					///		   i    /
					///        i   /
					///      C i /     
					
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which angle is closest to 90?
					if ( Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[1], _targetPoints[2]) - 90) && Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[0], _targetPoints[1]) - 90))
					{ // angle 0
						A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
						dir = tdir;
					} else if ( Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[1], _targetPoints[0]) - 90) && Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[0], _targetPoints[2]) - 90))
					{ // angle 1
						A = _targetPoints[1]; B = _targetPoints[2]; Ct = _targetPoints[0];
						dir = tdir;
					} else 
					{ // angle 2
						A = _targetPoints[2]; B = _targetPoints[0]; Ct = _targetPoints[1];
						dir = tdir;
					}
					ac = MathUtilities.distanceP(A, B);
					angBAC = Math.PI/2;
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ac * Math.sin(caori), A.y - ac * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "acute_isosceles_triangle":
				case "isosceles_acute_triangle":						
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which angle is greatest?
					if ( MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[1], _targetPoints[2]) && MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[0], _targetPoints[1]))
					{ // angle 0
						A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
						dir = tdir;
					} else if ( MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[1], _targetPoints[0]) && MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[0], _targetPoints[2]))
					{ // angle 1
						A = _targetPoints[1]; B = _targetPoints[2]; Ct = _targetPoints[0];
						dir = tdir;
					} else 
					{ // angle 2
						A = _targetPoints[2]; B = _targetPoints[0]; Ct = _targetPoints[1];
						dir = tdir;
					}
					ac = MathUtilities.distanceP(A, B);
					angBAC = MathUtilities.calcAcuteAngleBetween(B, Ct, A);
					if (angBAC >= Math.PI/2) angBAC = Math.PI/3; // default to 60 degrees for incorrect figures
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ac * Math.sin(caori), A.y - ac * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "obtuse_isosceles_triangle":
				case "isosceles_obtuse_triangle":
					///      A ------- B
					///		  /    /
					///      /  /
					///  C  //     
					
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which angle is greatest?
					if ( MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[1], _targetPoints[2]) && MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[0], _targetPoints[1]))
					{ // angle 0
						A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
						dir = tdir;
					} else if ( MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[1], _targetPoints[0]) && MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[0], _targetPoints[2]))
					{ // angle 1
						A = _targetPoints[1]; B = _targetPoints[2]; Ct = _targetPoints[0];
						dir = tdir;
					} else 
					{ // angle 2
						A = _targetPoints[2]; B = _targetPoints[0]; Ct = _targetPoints[1];
						dir = tdir;
					}
					ac = MathUtilities.distanceP(A, B);
					angBAC = MathUtilities.calcAcuteAngleBetween(B, Ct, A);
					if (angBAC <= Math.PI/2) angBAC = Math.PI/3*2; // default to 120 degrees for incorrect figures
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ac * Math.sin(caori), A.y - ac * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "right_scalene_triangle":
				case "scalene_right_triangle":
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which angle is closest to 90?
					if ( Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[1], _targetPoints[2]) - 90) && Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[0], _targetPoints[1]) - 90))
					{ // angle 0
						A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
						dir = tdir;
					} else if ( Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[1], _targetPoints[0]) - 90) && Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[0], _targetPoints[2]) - 90))
					{ // angle 1
						A = _targetPoints[1]; B = _targetPoints[2]; Ct = _targetPoints[0];
						dir = tdir;
					} else 
					{ // angle 2
						A = _targetPoints[2]; B = _targetPoints[0]; Ct = _targetPoints[1];
						dir = tdir;
					}
					ab = MathUtilities.distanceP(A, B);
					ac = MathUtilities.distanceP(A, Ct);
					angBAC = Math.PI/2;
					if (Math.abs(ab - ac) < DrawingPanel(this.parent).length_threshold_pixels)
					{
						ac = ac * .75;
						// just in case, make sure other pair aren't now equal too
						bc = MathUtilities.lawOfCosines(ab, ac, 0, angBAC);
						if ( Math.abs(bc - ab) < DrawingPanel(this.parent).length_threshold_pixels || Math.abs(bc - ac) < DrawingPanel(this.parent).length_threshold_pixels)
						{
							ac = ac * .67;	
						}
					}
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ac * Math.sin(caori), A.y - ac * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "acute_scalene_triangle":
				case "scalene_acute_triangle":							
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which angle is greatest?
					if ( MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[1], _targetPoints[2]) && MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[0], _targetPoints[1]))
					{ // angle 0
						A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
						dir = tdir;
					} else if ( MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[1], _targetPoints[0]) && MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) > MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[0], _targetPoints[2]))
					{ // angle 1
						A = _targetPoints[1]; B = _targetPoints[2]; Ct = _targetPoints[0];
						dir = tdir;
					} else 
					{ // angle 2
						A = _targetPoints[2]; B = _targetPoints[0]; Ct = _targetPoints[1];
						dir = tdir;
					}
					ab = MathUtilities.distanceP(A, B);
					ac = MathUtilities.distanceP(A, Ct);
					angBAC = MathUtilities.calcAcuteAngleBetween(B, Ct, A);
					if (angBAC >= Math.PI/2) angBAC = Math.PI/3; // default to 60 degrees for incorrect figures
					if (Math.abs(ab - ac) < DrawingPanel(this.parent).length_threshold_pixels)
					{
						ac = ac * .75;
						// just in case, make sure other pair aren't now equal too
						bc = MathUtilities.lawOfCosines(ab, ac, 0, angBAC);
						if ( Math.abs(bc - ab) < DrawingPanel(this.parent).length_threshold_pixels || Math.abs(bc - ac) < DrawingPanel(this.parent).length_threshold_pixels)
						{
							ac = ac * .67;	
						}
					}
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ac * Math.sin(caori), A.y - ac * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
				case "obtuse_scalene_triangle":
				case "scalene_obtuse_triangle":
					_targetPoints = addRandomPoints(targetPoints, 3-targetPoints.length);
					tcentroid = Polygon.Centroid(_targetPoints);
					tdir = MathUtilities.calcAcuteDirectionBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]);					
					// which angle is closest to 90?
					if ( Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[1], _targetPoints[2]) - 90) && Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[2], _targetPoints[0]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[0], _targetPoints[1]) - 90))
					{ // angle 0
						A = _targetPoints[0]; B = _targetPoints[1]; Ct = _targetPoints[2];
						dir = tdir;
					} else if ( Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[2], _targetPoints[1], _targetPoints[0]) - 90) && Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[0], _targetPoints[2], _targetPoints[1]) - 90) < Math.abs(MathUtilities.calcAcuteRotationBetween(_targetPoints[1], _targetPoints[0], _targetPoints[2]) - 90))
					{ // angle 1
						A = _targetPoints[1]; B = _targetPoints[2]; Ct = _targetPoints[0];
						dir = tdir;
					} else 
					{ // angle 2
						A = _targetPoints[2]; B = _targetPoints[0]; Ct = _targetPoints[1];
						dir = tdir;
					}
					ab = MathUtilities.distanceP(A, B);
					ac = MathUtilities.distanceP(A, Ct);
					angBAC = MathUtilities.calcAcuteAngleBetween(B, Ct, A);
					if (angBAC <= Math.PI/2) angBAC = Math.PI/3*2; // default to 120 degrees for incorrect figures
					if (Math.abs(ab - ac) < DrawingPanel(this.parent).length_threshold_pixels)
					{
						ac = ac * .75;
						// just in case, make sure other pair aren't now equal too
						bc = MathUtilities.lawOfCosines(ab, ac, 0, angBAC);
						if ( Math.abs(bc - ab) < DrawingPanel(this.parent).length_threshold_pixels || Math.abs(bc - ac) < DrawingPanel(this.parent).length_threshold_pixels)
						{
							ac = ac * .67;	
						}
					}
					baori = MathUtilities.calcAngle(B, A);
					caori = baori + dir * angBAC;
					C = new Point(A.x + ac * Math.sin(caori), A.y - ac * Math.cos(caori));
					I = Polygon.Centroid(new Array(A,B,C));				
					// turn A, B, and C into grow points
					ai = MathUtilities.distanceP(A, I);
					aiori = MathUtilities.calcAngle(A,I);
					bi = MathUtilities.distanceP(B, I);
					biori = MathUtilities.calcAngle(B,I);
					ci = MathUtilities.distanceP(C, I);
					ciori = MathUtilities.calcAngle(C,I);
					shape.x = I.x;
					shape.y = I.y;					
					points.push(new Point(0, 0)); growPoints.push(new Point(ai, aiori));
					points.push(new Point(0, 0)); growPoints.push(new Point(bi, biori));
					points.push(new Point(0, 0)); growPoints.push(new Point(ci, ciori));
					break;
			}
			// is this going to grow properly?
			//trace("child type", type);
			var returnarr:Array = MathUtilities.checkShapeType(targetPoints, type, DrawingPanel(this.parent).parallel_threshold_degrees, DrawingPanel(this.parent).length_threshold_pixels, DrawingPanel(this.parent).angle_threshold_degrees, DrawingPanel(this.parent).right_threshold_degrees);
			this.valid = returnarr[0];
			this.error = returnarr[1];
			
			// setup for growth
			fps = this.stage.frameRate;
			timestamp = flash.utils.getTimer();
			this.addEventListener(Event.ENTER_FRAME, grow);
		}
			/** In the cases where the container has less points than the given shape, add some random points */
			private function addRandomPoints (ipoints:Array, numExtra:int):Array
			{
				var opoints:Array = new Array();
				// get average distance of points from centroid
				var sum:Number = 0;
				var c:Point = MathUtilities.centroid(ipoints);
				for each (var p:Point in ipoints)
				{
					sum += MathUtilities.distanceP(c, p);
					opoints.push(p);
				}
				if (numExtra > 0)
				{
					var avg:Number = sum/ipoints.length;
					for (var i:uint=0; i < numExtra; i++)
					{
						var ang:Number = Math.PI*2*Math.random() - Math.PI;
						opoints.push(new Point(c.x+avg*Math.sin(ang), c.y-avg*Math.cos(ang)));
					}
				}
				opoints = MathUtilities.orderPointsPolygon(opoints);
				return opoints;
			}
		
		/** The grow function uses the polar coordinates to grow the shape from the centroid outwards */
		private function grow(event:Event):void
		{
			var cancel:Boolean = false;
			if (flash.utils.getTimer() - timestamp < GROW_ANIMATION_TIME)
			{
				// get the percentage of total growth for this grow step
				var step:Number = 1/Math.ceil((GROW_ANIMATION_TIME/1000)*fps);
				//trace(step);
				// setup shape
				shape.graphics.clear();
				shape.graphics.lineStyle(2, OUTLINE_COLOR);
				shape.graphics.beginFill(INTERIOR_COLOR);
				for (var i:uint=0; i < points.length; i++)
				{
					var pp:Point = growPoints[(starti+i)%growPoints.length];
					var cp:Point = points[(starti+i)%points.length];
					cp.x += pp.x*step * Math.sin(pp.y);
					cp.y += pp.x*step * -Math.cos(pp.y);
					if (!valid && !closedPolygon.pointWithinBounds(shape.localToGlobal(new Point(cp.x, cp.y))))
					{
						cancel = true;
					}
					//trace(cp, pp, shape.x, shape.y);
					if (i == 0)
					{
						shape.graphics.moveTo(cp.x, cp.y);
					} else
					{
						shape.graphics.lineTo(cp.x, cp.y);
					}
				}
				shape.graphics.lineTo(points[starti].x, points[starti].y);
				shape.graphics.endFill();
				if (cancel)
				{
					this.removeEventListener(Event.ENTER_FRAME, grow);
					this.cancelGrowAnimation();
				}
			} else
			{
				this.removeEventListener(Event.ENTER_FRAME, grow);
				if (valid)
				{
					this.completeGrowAnimation();
				} else
				{
					this.cancelGrowAnimation();
				}
			}
		}
		/** Not a valid figure, allow user to view the incorrect shape over the target area until click */
		private function cancelGrowAnimation():void
		{
			// color area for target shape
			this.graphics.beginFill(0xFF0000);
			this.graphics.moveTo(targetDrawPoints[targetDrawPoints.length-1].x, targetDrawPoints[targetDrawPoints.length-1].y);
			for each (var p:DrawPoint in targetDrawPoints)
			{
				this.graphics.lineTo(p.x, p.y);
			}
			this.graphics.endFill();
			GeometryGameItem(parent.parent).processCommand("child", "error", this, new Array(error));
		}
		/** Growing of shape is done, check to see if the shape is valid, if so complete the shape, else cancel */
		private function completeGrowAnimation():void
		{
			// CHECK TO SEE IF THIS SHAPE IS VALID
			startChildAnimation();
		}
		
		/** The final animation colors the shape yellow (like a chick), draws a face, and "pops" the child shape out of its container */
		private function startChildAnimation():void
		{
			// redraw the shape in yellow
			shape.graphics.clear();
			shape.graphics.lineStyle(2, FINAL_OUTLINE_COLOR);
			shape.graphics.beginFill(FINAL_INTERIOR_COLOR);
			shape.graphics.moveTo(points[points.length-1].x, points[points.length-1].y);
			for (var i:uint=0; i < points.length; i++)
			{
				shape.graphics.lineTo(points[i].x, points[i].y);
			}
			shape.graphics.endFill();
			var s:Number;
			if (points != null)
			{
				var maxDim:Number = Math.max(MathUtilities.findBoundingWidth(points),MathUtilities.findBoundingHeight(points));
				s =	2*ShapeProductionTask.unit*MathUtilities.area(points)/(maxDim*maxDim);
				//if (points.length > 3) s = 2*s;
			} 
			var r:int, g:int, b:int;
			r = color & 0xFF0000; r = r >> 16;
			g = color & 0x00FF00; g = g >> 8;
			b = color & 0x0000FF;
			var dr:int = r-r/4; if (dr < 0) dr = 0;
			var dg:int = g-g/4; if (dg < 0) dg = 0;
			var db:int = b-b/4; if (db < 0) db = 0;
			//trace("post", "r", byte2bin(r), "g", byte2bin(g), "b", byte2bin(b));
			var darkColor:uint = dr << 16 | dg << 8 | db;
			var irisColor:uint = Math.ceil(0xAAAAAA * Math.random()) + 0x333333;
			eyeL = new Eye(15*s, 20*s, FINAL_OUTLINE_COLOR, darkColor,irisColor, Eye.LEFT);
			eyeR = new Eye(15*s, 20*s, FINAL_OUTLINE_COLOR, darkColor,irisColor, Eye.RIGHT);
			eyeL.x = -10*s;
			eyeL.y = -20*s;
			eyeR.x = 10*s;
			eyeR.y = -20*s;
			shape.addChild(eyeL);
			shape.addChild(eyeR);
			nose = new Shape();
			nose.graphics.lineStyle(3*s, FINAL_OUTLINE_COLOR);
			nose.graphics.beginFill(FINAL_INTERIOR_COLOR);
			nose.graphics.drawEllipse(-8*s,-8*s,16*s,16*s);
			nose.graphics.endFill();
			nose.graphics.lineStyle(4*s, FINAL_INTERIOR_COLOR);
			nose.graphics.beginFill(FINAL_INTERIOR_COLOR);
			nose.graphics.drawRect(-8*s, -8*s, 16*s, 8*s);
			nose.graphics.endFill();
			
			shape.addChild(nose);
			mouth = new Mouth(30*s, 15*s, FINAL_OUTLINE_COLOR);
			mouth.y = 12*s;
			shape.addChild(mouth);
			
			timestamp = getTimer();
			distanceToEdge = 0;
			this.addEventListener(Event.ENTER_FRAME, childAnimation);
		}
		private function childAnimation(event:Event):void
		{
			var curTime:int = getTimer() - timestamp;
			if (curTime < FINAL_ANIMATION_TIME)
			{
				if (curTime < FINAL_ANIMATION_TIME/4 )
				{
					ishapePoint = new Point(shape.x, shape.y);
				}
				else if (curTime > FINAL_ANIMATION_TIME/4 && curTime < FINAL_ANIMATION_TIME/2)
				{ // pop out of box
					var curProp:Number = (curTime - FINAL_ANIMATION_TIME/4)/(FINAL_ANIMATION_TIME/4);
					// moves linearly in x direction
					var mag:Number = 100/(fps*FINAL_ANIMATION_TIME/4000); 
					shape.x = ishapePoint.x - curProp*shape.width;
					// x = 0, x = -100::: (x - 0) (x + 100) ::: x2 - 100x
					shape.y = ishapePoint.y + curProp*curProp*shape.width - curProp*shape.width;
					
				}
				else if (curTime > FINAL_ANIMATION_TIME/2)
				{	//move off screen to the left
					
					//trace(shape.x, shape.y, this.x, this.y, this.parent.x, this.parent.y);
					if (distanceToEdge == 0) distanceToEdge = MathUtilities.distance(shape.x+shape.width, shape.y, 0, shape.y);
					shape.x -= distanceToEdge/(fps*FINAL_ANIMATION_TIME/2000);
				}
				if (!mouth.blinking)
				{
					// give blinking a 1 in 10*framerate chance of occurring
					if (Math.floor(Math.random()*fps*5) == 0)
					{
						mouth.blink();
					}
				}
				if (!this.eyeL.blinking)
				{
					// give blinking a 1 in 10*framerate chance of occurring
					if (Math.floor(Math.random()*fps*10) == 0)
					{
						eyeL.blink();
						eyeR.blink();
					}
				}	
			} else	
			{
				completeChildAnimation();
			}
		}
		private function completeChildAnimation():void
		{
			this.removeEventListener(Event.ENTER_FRAME, childAnimation);
			closedPolygon.childPolygon = this;
			trace(parent, type);
			GeometryGameItem(parent.parent).processCommand("child", "initiate", this, new Array(type));
			//this.dispatchEvent(new Event(Event.COMPLETE));
		}
	}
}